
package stcu;

import com.nvlled.route.*;
import stcu.robjects.*;
import java.util.*;
import java.net.*;

public class ClientAuth 
  implements ObjectReceiver<Login.Status> {

    private static final long LOGIN_TIMEOUT = 5000; // milliseconds

    private ObjectRouter router;
    private Prober prober;
    private boolean loggingIn;
    private boolean authenticated = false;
    private String idNumber = "";
    private Thread timeoutThread = Thread.currentThread();

    public Runnable loginHook;
    public Runnable logoutHook;
    public Runnable timeOutHook;

    private boolean loginFailed = false;

    public ClientAuth(ObjectRouter router) {
        this.router = router;
        router.subscribe(Login.Status.class, this);
        initializeListeners();
    }

    private void initializeListeners() {
        loginHook = new Runnable() { public void run() {}};
        logoutHook = new Runnable() { public void run() {}};
        timeOutHook = new Runnable() { public void run() {}};
    }

    public void receive(Login.Status status) {
        if (loggingIn) {
            if (status.getCode().equals("ok")) {
                timeoutThread.interrupt();

                loggingIn = false;
                AddressTable table =  router.getTable();
                String serverName = status.getSource();
                table.store("default", status.getSourceAddress());
                authenticated = true;
                idNumber = status.getIdNumber();

                loginHook.run();
            } else {
                loginFailed = true;
            }
        }
    }

    public String getLoginId() {
        return idNumber;
    }

    public boolean isAuthenticated() {
        return authenticated;
    }

    public void login(String username) {
        loggingIn = true;
        loginFailed = false;
        Login login = new Login(username);
        List<String> names = getServerNames();
        if (names == null || names.isEmpty()) {
            throw new NoServerException();
        }

        router.deliver(login, names);

        Thread timeoutThread = new Thread() { 
            public void run() { 
                try { Thread.sleep(LOGIN_TIMEOUT); } 
                catch (Exception e) {  }
                timeOut(); 
            }
        };
        timeoutThread.start();
    }

    public void setLoginHook(Runnable hook) {
        if (hook != null) {
            loginHook = hook;
        }
    }

    public void setTimeOutHook(Runnable hook) {
        if (hook != null) {
            timeOutHook = hook;
        }
    }

    public void setLogoutHook(Runnable hook) {
        if (hook != null) {
            logoutHook = hook;
        }
    }

    //public void login(String idNumber) {
    //    Login login = new Login(idNumber);
    //    List<String> ips = null;

    //    if (ips == null || ips.isEmpty()) {
    //        throw new NoServerException();
    //    }
    //    OrderInfo info = new OrderInfo(
    //            LoginStatus.class,
    //            prober.getServerCount(),
    //            LOGIN_TIMEOUT);

    //    router.deliverSync(login);
    //    loggingIn = true;
    //}
    
    private List<String> getServerNames() {
        List<String> names = new ArrayList<String>();
        AddressTable table = router.getTable();
        for(String name: table.getNames()) {
            if (name.startsWith(Prober.SERVER_PREFIX)) {
                names.add(name);
            }
        }
        return names;
    }

    public boolean isLoginFailed() {
        return loginFailed;
    }

    public void timeOut() {
        if (loggingIn) {
            loggingIn = false;
            timeOutHook.run();
        }
    }

    public void logout() {
        if (authenticated) {
            idNumber = "";
            authenticated = false;
            router.deliver(new Logout(), "default");
            logoutHook.run();
        }
    }

}



